using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.ComponentModel;
using System.Globalization;
using System.Diagnostics;

namespace MyPhotoIndex.Controls
{
    //DefaultEvent("") typeof(ControlsUtil.ColorProgressBar)
    [Designer(typeof(ColorProgressBarDesigner)), ToolboxItem(true)]
    [DefaultProperty("Value")]
    [ToolboxBitmap(typeof(ColorProgressBar), "Resources.Controls.ColorProgressBar.bmp")]
    public class ColorProgressBar : Control
    {
        public ColorProgressBar()
            : base()
        {
            FullColor = Color.LightSkyBlue;
            //ForeColor = SystemColors.Desktop;
            toolTip1 = new ToolTip();
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.DoubleBuffered = true;
        }

        //UserControl overrides dispose to clean up the component list.
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (toolTip1 != null)
                {
                    toolTip1.Dispose();
                    toolTip1 = null;
                }
            }
            base.Dispose(disposing);
        }

        ////Required by the Windows Form Designer
        //private System.ComponentModel.IContainer components;
        ////NOTE: The following procedure is required by the Windows Form Designer
        ////It can be modified using the Windows Form Designer.  
        ////Do not modify it using the code editor.
        //[System.Diagnostics.DebuggerStepThrough()]
        //private void InitializeComponent()
        //{
        //    //
        //    //ColorProgressBar
        //    //
        //    this.Name = "ColorProgressBar";
        //    this.Size = new System.Drawing.Size(376, 32);
        //}

        private const string Catagory = "ProgressBar";
        private ToolTip toolTip1;
        //[Editor(typeof(System.Windows.Forms.Design.FolderNameEditor),
        //typeof(System.Drawing.Design.UITypeEditor))]
        //http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemWindowsFormsDesignFolderNameEditorClassTopic.asp

        private Timer m_marqueeTimer;

        private int m_value = 0;
        [Category(Catagory), Description("Value"), DefaultValue(0)]
        public int Value
        {
            get { return m_value; }
            set
            {
                if (value < Minimum/* || value > Maximum*/)
                {
                    throw new ArgumentOutOfRangeException("Value", value, "Value must be in the range between Minimum and Maximum");
                }

                if (value > Maximum)
                {
                    m_value = Maximum;
                }

                m_value = value;
                Invalidate();
                //Refresh()
            }
        }

        private int m_minimum;
        [Category(Catagory), Description("Minimum"), DefaultValue(0)]
        public int Minimum
        {
            get { return m_minimum; }
            set
            {
                m_minimum = value;
                Invalidate();
            }
        }

        private int m_maximum = 10;
        [Category(Catagory), Description("Maximum"), DefaultValue(10)]
        public int Maximum
        {
            get { return m_maximum; }
            set
            {
                if (value < Minimum)
                {
                    throw new ArgumentOutOfRangeException("Maximum", value, "Maximum Value Cannot be lower then minimum value");
                }
                m_maximum = value;
                Invalidate();
            }
        }

        private int m_borderWidth = 1;
        [Category(Catagory), Description("Border Width"), DefaultValue(1)]
        public int BorderWidth
        {
            get { return m_borderWidth; }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException("BorderWidth", value, "Value must be a positive integer");
                }
                m_borderWidth = value;
                Invalidate();
            }
        }

        private Color m_borderColor = Color.Black;
        [Category(Catagory), Description("Border Color")] //, DefaultValue(Color.Black)]
        public Color BorderColor
        {
            get { return m_borderColor; }
            set
            {
                m_borderColor = value;
                Invalidate();
            }
        }

        private string m_text;
        [Localizable(true)]
        public override string Text
        {
            get { return m_text; }
            set
            {
                m_text = value;
                Invalidate();
            }
        }

        private bool m_showPercent;
        [Category(Catagory), Description("Show Percent")]
        public bool ShowPercent
        {
            get { return m_showPercent; }
            set { m_showPercent = value; }
        }

        private bool m_office2007Style;
        [Category(Catagory), Description("Office2007Style")]
        [RefreshProperties(RefreshProperties.All)]
        public bool Office2007Style
        {
            get { return m_office2007Style; }
            set
            {
                m_office2007Style = value;
                m_borderWidth = 2;
            }
        }

        private ProgressBarStyle m_style;
        [Category(Catagory), Description("Style")]
        [RefreshProperties(RefreshProperties.All)]
        public ProgressBarStyle Style
        {
            get { return m_style; }
            set
            {
                if (m_style == value)
                {
                    return;
                }
                m_style = value;
                if (m_marqueeTimer != null)
                {
                    m_marqueeTimer.Dispose();
                    m_marqueeTimer = null;
                }
                if (m_style == ProgressBarStyle.Marquee)
                {
                    m_marqueeValue = 0;
                    m_marqueeTimer = new Timer();
                    m_marqueeTimer.Interval = 100;
                    m_marqueeTimer.Tick += new EventHandler(m_marqueeTimer_Tick);
                    m_marqueeTimer.Start();
                }
            }
        }

        private void m_marqueeTimer_Tick(object sender, EventArgs e)
        {
            int pw = Width - m_borderWidth;
            int dx = (int)(pw * 0.05f);
            m_marqueeValue = (m_marqueeValue + dx) % pw;
            this.Invalidate();
        }

        private int m_marqueeValue;

        private string m_toolTip;
        [Localizable(true)]
        [Category(Catagory), Description("Tooltip")]
        public string ToolTip
        {
            get { return m_toolTip; }
            set
            {
                m_toolTip = value;
                toolTip1.SetToolTip(this, value);
                //Invalidate()
            }
        }

        //private Color m_textColor = Color.Snow;
        //[Category(Catagory), Description("Text Color")]
        //public Color TextColor
        //{
        //    get { return m_textColor; }
        //    set
        //    {
        //        m_textColor = value;
        //        Invalidate();
        //    }
        //}

        private Color m_backgroundGradientColor = Color.Snow;
        [Category(Catagory), Description("Gradient Color")]
        public Color BackgroundGradientColor
        {
            get { return m_backgroundGradientColor; }
            set
            {
                m_backgroundGradientColor = value;
                Invalidate();
            }
        }

        private Color m_fullGradientColor = Color.Snow;
        [Category(Catagory), Description("Gradient Color")]
        public Color FullGradientColor
        {
            get { return m_fullGradientColor; }
            set
            {
                m_fullGradientColor = value;
                Invalidate();
            }
        }

        private Color m_fullColor = Color.Snow;
        [Category(Catagory), Description("Gradient Color")]
        public Color FullColor
        {
            get { return m_fullColor; }
            set
            {
                m_fullColor = value;
                Invalidate();
            }
        }

        private ContentAlignment m_textAlign = ContentAlignment.MiddleCenter;
        [Category(Catagory), Description("Text Alignment"), DefaultValue(ContentAlignment.MiddleCenter)]
        public ContentAlignment TextAlign
        {
            get { return m_textAlign; }
            set
            {
                m_textAlign = value;
                Invalidate();
            }
        }

        private bool m_gradient = true;
        [Category(Catagory), Description("Gradient"), DefaultValue(false)]
        public bool Gradient
        {
            get { return m_gradient; }
            set
            {
                m_gradient = value;
                Invalidate();
            }
        }

        private bool m_flat;
        [Category(Catagory), Description("Text Alignment"), DefaultValue(false)]
        public bool Flat
        {
            get { return m_flat; }
            set
            {
                m_flat = value;
                Invalidate();
            }
        }

        public void Increment(string message)
        {
            Value++;
            if (message != null)
            {
                Text = message;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            //using (Image offScreen = new Bitmap(Width, Height))
            //using (Graphics osGraphics = Graphics.FromImage(offScreen))
            //{
            //, PixelFormat.PixelFormat32BppArgb
            //if (osGraphics == null)
            //{
            //    osGraphics = Graphics.FromImage(offScreen);
            //}
            //Lock HDC
            //IntPtr hdc = osGraphics.GetHdc();

            //draw the progressBar body
            if (m_office2007Style == true)
            {
                if (m_style == ProgressBarStyle.Marquee)
                {
                    DrawOffice2007Marquee(g, e.ClipRectangle);
                }
                else
                {
                    DrawOffice2007(g, e.ClipRectangle);
                }
                DrawOffice2007Border(g, e.ClipRectangle);
            }
            else
            {

                //g.FillRectangle(Brushes.Wheat, 0, 0, Width, Height);

                //using (Pen pen = new Pen(Color.Black, 4))
                //{
                //    g.DrawRectangle(pen, 10, 10, 6, 6);
                //}
                if (m_flat == true)
                {
                    Draw2D(g);
                }
                else
                {
                    Draw3D(g);
                }
                DrawText(g);
                DrawBorder(g);
            }

            // Release the HDC
            //osGraphics.ReleaseHdc(hdc);
            //osGraphics = null;
            //GC.Collect();
            // Then blit it all
            //g.DrawImageUnscaled(offScreen, 0, 0);
            //}
        }

        private void DrawOffice2007Marquee(Graphics g, Rectangle clipRegion)
        {
            //int marqueeAnimationSpeed = 100;
            //DrawOffice2007Background(g);


            int pipeHeight = Height - (m_borderWidth * 2);
            Rectangle r = new Rectangle(m_borderWidth, m_borderWidth, Width - (m_borderWidth * 2), pipeHeight);
            DrawOffice2007Background(g, r);
            r = new Rectangle(m_borderWidth + m_marqueeValue, m_borderWidth, 30, pipeHeight);
            DrawOffice2007Pipe(g, r);

            //if (m_borderWidth + m_marqueeValue + 30 >= (Width - m_borderWidth))
            //{
            //    Rectangle r = new Rectangle(m_borderWidth + m_marqueeValue, m_borderWidth, 30, pipeHeight);
            //    DrawOffice2007Pipe(g, r);
            //}
        }

        private void DrawOffice2007Pipe(Graphics g, Rectangle pipeRectangle)
        {
            int pipeHeight = pipeRectangle.Height;
            int topHeight = pipeHeight / 2;
            int bottomHeight = pipeHeight - topHeight;

            //draw value bottom - bottom half pipe
            Rectangle rectangle = new Rectangle(pipeRectangle.X, pipeRectangle.Y + pipeRectangle.Height / 2, pipeRectangle.Width, bottomHeight);
            Color color1 = Color.FromArgb(102, 147, 32);
            Color color2 = Color.FromArgb(203, 227, 159);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 0F))
            {
                g.FillRectangle(gradientBrush, rectangle);
            }

            //draw value top - top half pipe
            rectangle = new Rectangle(pipeRectangle.X, pipeRectangle.Y, pipeRectangle.Width, topHeight);
            color1 = Color.FromArgb(216, 229, 195);
            color2 = Color.FromArgb(137, 177, 72);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 90F))
            {
                g.FillRectangle(gradientBrush, rectangle);
            }

            //draw light 1px line at the end of full pipe
            color1 = Color.FromArgb(252, 255, 245);
            color2 = Color.FromArgb(216, 235, 183);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 90F))
            using (Pen pen = new Pen(gradientBrush, 1))
            {
                int x1 = pipeRectangle.Right;
                g.DrawLine(pen, x1, pipeRectangle.Y, x1, pipeRectangle.Height);
            }

            rectangle = new Rectangle(pipeRectangle.Right, pipeRectangle.Y, 4, pipeRectangle.Height);
            DrawOffice2007BackgroundShadow(g, rectangle);
        }

        internal void DrawOffice2007(Graphics g, Rectangle clipRegion)
        {
            //m_borderWidth = 2;
            int width = GetPipeWidth();

            DrawOffice2007Background(g);

            if (m_value <= m_minimum)
            {
                return;
            }

            int pipeHeight = Height - (m_borderWidth * 2);
            int topHeight = pipeHeight / 2;
            int bottomHeight = pipeHeight - topHeight;

            //draw value bottom - bottom half pipe
            Rectangle rectangle = new Rectangle(m_borderWidth, Height / 2, width, bottomHeight);
            Color color1 = Color.FromArgb(102, 147, 32);
            Color color2 = Color.FromArgb(203, 227, 159);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 0F))
            {
                g.FillRectangle(gradientBrush, rectangle);
            }

            //draw value top - top half pipe
            rectangle = new Rectangle(m_borderWidth, m_borderWidth, width, topHeight);
            color1 = Color.FromArgb(216, 229, 195);
            color2 = Color.FromArgb(137, 177, 72);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 90F))
            {
                g.FillRectangle(gradientBrush, rectangle);
            }

            //draw light 1px line at the end of full pipe
            color1 = Color.FromArgb(252, 255, 245);
            color2 = Color.FromArgb(216, 235, 183);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 90F))
            using (Pen pen = new Pen(gradientBrush, 1))
            {
                int x1 = width + m_borderWidth;
                g.DrawLine(pen, x1, m_borderWidth, x1, Height - (m_borderWidth * 2));
            }

            //value overlay
            //color1 = Color.FromArgb(0, 216, 229, 195);
            //color2 = Color.FromArgb(100, 150, 207, 67);
            //using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 0F))
            //{
            //    int valueWidth = (int)((double)width * 0.7f);
            //    int x = (width - valueWidth) + m_borderWidth;
            //    g.FillRectangle(gradientBrush, x, m_borderWidth, valueWidth, Height - (m_borderWidth * 2));
            //}
        }

        private void DrawOffice2007Background(Graphics g)
        {
            int width = GetPipeWidth();
            //draw background
            if (m_value >= m_maximum)
            {
                return;
            }

            Rectangle rectangle = new Rectangle(m_borderWidth + width, m_borderWidth, (Width - width) - (m_borderWidth * 2), Height - (m_borderWidth * 2));

            if (rectangle.Width == 0 ||
                rectangle.Height <= 0)
            {
                return;
            }
            DrawOffice2007Background(g, rectangle);

            //start background blur
            Color color1 = Color.FromArgb(100, 178, 185, 200);
            Color color2 = Color.FromArgb(0, 175, 201, 215);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 0F))
            {
                g.FillRectangle(gradientBrush, width + m_borderWidth + 1, m_borderWidth, 4, Height - (m_borderWidth * 2));
            }
        }

        private void DrawOffice2007Background(Graphics g, Rectangle rectangle)
        {
            if (rectangle.Width <= 0 || 
                rectangle.Height <= 0)
            {
                return;
            }

            Color color1 = Color.FromArgb(198, 203, 213);
            Color color2 = Color.FromArgb(224, 228, 237);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 90F))
            {
                g.FillRectangle(gradientBrush, rectangle);
            }
        }

        private void DrawOffice2007BackgroundShadow(Graphics g, Rectangle rectangle)
        {
            //start background blur
            Color color1 = Color.FromArgb(100, 178, 185, 200);
            Color color2 = Color.FromArgb(0, 175, 201, 215);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 0F))
            {
                g.FillRectangle(gradientBrush, rectangle);
            }
        }

        private void DrawOffice2007Border(Graphics g, Rectangle clipRegion)
        {
            //outer 1px rectangle
            Point[] points = new Point[8];
            points[0] = new Point(0, 1);
            points[1] = new Point(1, 0);
            points[2] = new Point(Width - 2, 0);
            points[3] = new Point(Width - 1, 1);
            points[4] = new Point(Width - 1, Height - 2);
            points[5] = new Point(Width - 2, Height - 1);
            points[6] = new Point(1, Height - 1);
            points[7] = new Point(0, Height - 2);

            Color color = Color.FromArgb(248, 251, 255);
            using (Pen pen = new Pen(color, 1))
            //using (GraphicsPath path = new GraphicsPath())
            {
                //g.DrawPath(pen, path);
                g.DrawClosedCurve(pen, points, 0f, FillMode.Alternate);
            }

            //inner 1px rectangle
            points = new Point[8];
            points[0] = new Point(0 + 1, 1 + 1);
            points[1] = new Point(1 + 1, 0 + 1);
            points[2] = new Point(Width - 2 - 1, 0 + 1);
            points[3] = new Point(Width - 1 - 1, 1 + 1);
            points[4] = new Point(Width - 1 - 1, Height - 2 - 1);
            points[5] = new Point(Width - 2 - 1, Height - 1 - 1);
            points[6] = new Point(1 + 1, Height - 1 - 1);
            points[7] = new Point(0 + 1, Height - 2 - 1);

            color = Color.FromArgb(110, 151, 204);
            using (Pen pen = new Pen(color, 1))
            {
                g.DrawClosedCurve(pen, points, 0f, FillMode.Alternate);
            }

            //Rectangle rectangle = new Rectangle(0, 0, Width - 1, Height - 1);
            //using (Pen pen = new Pen(color, 1f))
            //{
            //    g.DrawRectangle(pen, rectangle);
            //}

            ////inner 1px rectangle
            //rectangle = new Rectangle(1, 1, Width - 3, Height - 3);
            //color = Color.FromArgb(110, 151, 204);
            //using (Pen pen = new Pen(color, 1f))
            //{
            //    g.DrawRectangle(pen, rectangle);
            //}

            ////punch a pixel
            //color = Color.FromArgb(155, 186, 227);

            //using (Pen pen = new Pen(color, 1f))
            //{
            //    Point p = new Point(1, 1);
            //    Point p1 = new Point(p.X, p.Y);
            //    p1.Offset(1, 1);
            //    g.DrawLine(pen, p, p1);
            //    p.Y = Height - 1;
            //    p1 = new Point(p.X, p.Y);
            //    p1.Offset(1, 1);
            //    g.DrawLine(pen, p, p1);

            //    p.X = Width - 1;
            //    p1 = new Point(p.X, p.Y);
            //    p1.Offset(1, 1);
            //    g.DrawLine(pen, p, p1);

            //    p.Y = 1;
            //    p1 = new Point(p.X, p.Y);
            //    p1.Offset(1, 1);
            //    g.DrawLine(pen, p, p1);
            //}
        }

        /// <summary>
        /// draw the progressbar text
        /// </summary>
        /// <param name="g"></param>
        private void DrawText(Graphics g)
        {
            if (m_showPercent == true)
            {
                m_text = string.Format(CultureInfo.InvariantCulture, "{0}/{1}", Value, Maximum);
            }
            if (m_text != null)
            {
                using (SolidBrush brushText = new SolidBrush(ForeColor))
                {
                    g.DrawString(m_text, Font, brushText, GetTextPosition());
                }
            }
        }

        private void Draw2D(Graphics g)
        {
            if (m_value > 0 && Width > 0 && Height > 0)
            {
                Rectangle rectangle = new Rectangle(0, 0, Width, Height);
                rectangle.Width = GetPipeWidth();
                Debug.WriteLine("rectangle.Width" + rectangle.Width);
                if (rectangle.Width <= 0)
                {
                    return;
                }
                using (Brush brush = CreatePipeBrush(rectangle))
                {
                    g.FillRectangle(brush, rectangle);
                }
            }
        }

        private int GetPipeWidth()
        {
            return (int)Math.Ceiling((Convert.ToDouble(m_value) / Convert.ToDouble(m_maximum)) * (Width - m_borderWidth));
        }

        private Brush CreatePipeBrush(Rectangle rectangle)
        {
            if (m_gradient == true)
            {
                return new LinearGradientBrush(rectangle, BackColor, FullColor, 45F);
            }
            else
            {
                return new SolidBrush(FullColor);
            }
        }

        private void Draw3D(Graphics g)
        {
            int valueWidth = GetPipeWidth();
            if (m_value > m_minimum)
            {
                //draw value part
                DrawPipe(g, FullColor, FullGradientColor, 0, 0, valueWidth, Height);
            }
            //draw empty part
            if (m_value < m_maximum || m_value == m_minimum)
            {
                DrawPipe(g, BackColor, BackgroundGradientColor, valueWidth, 0, Width - valueWidth, Height);
            }
        }

        /// <summary>
        /// draw a 3d pipe
        /// </summary>
        /// <param name="g"></param>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        private static void DrawPipe(Graphics g, Color color1, Color color2, int x, int y, int width, int height)
        {
            if (width == 0 || height == 0)
            {
                return;
            }
            //3d top
            int topHalfHeight = (int)Math.Ceiling(((Convert.ToDouble(height)) / 2d));
            Rectangle rectangle = new Rectangle(x, y, width, topHalfHeight);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 270F))
            //using (SolidBrush gradientBrush = new SolidBrush(color1))
            {
                g.FillRectangle(gradientBrush, rectangle);
            }
            //3d bottom
            rectangle = new Rectangle(x, y + topHalfHeight, width, height - topHalfHeight);
            using (LinearGradientBrush gradientBrush = new LinearGradientBrush(rectangle, color1, color2, 90F))
            //using (SolidBrush gradientBrush = new SolidBrush(color1))
            {
                g.FillRectangle(gradientBrush, rectangle);
            }
            //3d - right
            //3d - left
            //rectangle = New Rectangle(x, y, 5, CInt(height / 2))
            //oGradientBrush = New LinearGradientBrush(rectangle, color1, color2, 315)
            //g.FillRectangle(oGradientBrush, rectangle)
            //rectangle = New Rectangle(x, y + CInt(height / 2), 5, height - CInt(height / 2))
            //oGradientBrush = New LinearGradientBrush(rectangle, color1, color2, 135)
            //g.FillRectangle(oGradientBrush, rectangle)
        }

        /// <summary>
        /// draw the border
        /// </summary>
        /// <param name="g"></param>
        private void DrawBorder(Graphics g)
        {
            if (m_borderWidth <= 0) return;

            //draw rectangle draws the pen in the center of the rectangle border lines, so the pen goes half extent
            //out of the rectangle and half in
            int bw = m_borderWidth / 2;
            using (Pen pen = new Pen(BorderColor, m_borderWidth))
            {
                g.DrawRectangle(pen, bw, bw, Width - m_borderWidth, Height - m_borderWidth);
            }
        }

        public void SetText(string text, string[] @params)
        {
            this.Text = string.Format(CultureInfo.InvariantCulture, text, @params);
        }

        private PointF GetTextPosition()
        {
            return PointF.Empty;
         //   return Util.GetPosition(TextAlign, GetFontSize(), this);
        }

        private Size GetFontSize()
        {
            return Size.Empty;
           // return Util.GetFontSize(m_text, this);
            //// Measure the Specified String that is Drawn with Specified Font
            //Graphics g = CreateGraphics();
            //int offset = Convert.ToInt32(Math.Ceiling(g.MeasureString(" ", Font).Width));
            //int newWidth = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(g.MeasureString(m_text, Font).Width))) + offset;
            //int height = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(g.MeasureString(m_text, Font).Height)));
            //Size textSize = new Size();
            //textSize.Height = height;
            //textSize.Width = newWidth;
            //return textSize;
        }

        private void ColorProgressBar_SizeChanged(object sender, EventArgs e)
        {
            Invalidate();
        }
    }
}